package wangwenjun.phase2.concurrencypattern.producerconsumer.waitnotify;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author ChangLiang
 * @date 2020/6/10
 */
public class AppTest {

    /**
     * 假设提交
     * Event 几乎没有任何延迟，而处理Event 可能要花费比提交更多的时间，
     * 一个producer 一个consumer
     */
    @Test
    @DisplayName("one producer & one consumer")
    public void test() {
        final EventQueue eventQueue = new EventQueue();
        new Thread(() ->
        {
            for (; ; ) {
                eventQueue.offer(new EventQueue.Event());
            }
        }, "Producer").start();

        new Thread(() ->
        {
            for (; ; ) {
                eventQueue.take();
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer").start();
    }

    @Test
    @DisplayName("multi producers and multi consumers")
    public void test2() throws InterruptedException {
        final EventQueue eventQueue = new EventQueue();
        IntStream.range(0, 2).forEach(i -> new Thread(() -> {
            while (true) {
                ThreadUtil.sleepForMilliSeconds(ThreadLocalRandom.current().nextInt(200, 1000));
                eventQueue.offer(new EventQueue.Event());
            }
        }, "producer-thread-" + i).start());
        IntStream.range(0, 3).forEach(i -> new Thread(() -> {
            while (true) {
                ThreadUtil.sleepForMilliSeconds(ThreadLocalRandom.current().nextInt(200, 1000));
                eventQueue.take();
            }
        }, "consumer-thread-" + i).start());

        Thread.currentThread().join();
    }

    @Test
    @DisplayName("multi producers and multi consumers")
    public void test3() throws InterruptedException {
        final EventQueue eventQueue = new EventQueue();
        IntStream.range(0, 3).forEach(i -> new Thread(() -> {
            while (true) {
                ThreadUtil.sleepForMilliSeconds(ThreadLocalRandom.current().nextInt(200, 1000));
                eventQueue.offer(new EventQueue.Event());
            }
        }, "producer-thread-" + i).start());
        IntStream.range(0, 2).forEach(i -> new Thread(() -> {
            while (true) {
                ThreadUtil.sleepForMilliSeconds(ThreadLocalRandom.current().nextInt(200, 1000));
                eventQueue.take();
            }
        }, "consumer-thread-" + i).start());

        Thread.currentThread().join();
    }
}
